﻿using Fishing.Common;
using Fishing.Model;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows.Input;

namespace Fishing.Converter
{
    internal class SettingsJsonConverter : JsonConverter<Settings>
    {
        public override Settings? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.StartObject)
            {
                throw new JsonException();
            }

            var settings = new Settings();

            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.EndObject)
                {
                    return settings;
                }

                if (reader.TokenType == JsonTokenType.PropertyName)
                {
                    var propertyName = reader.GetString();

                    reader.Read();
                    switch (propertyName)
                    {
                        case nameof(settings.Startup):
                            settings.Startup = reader.GetBoolean();
                            break;
                        case nameof(settings.TaskbarIconVisible):
                            settings.TaskbarIconVisible = reader.GetBoolean();
                            break;
                        case nameof(settings.IncreaseMode):
                            settings.IncreaseMode = (IncreaseMode)reader.GetInt32();
                            break;
                        case nameof(settings.IncreaseAlgorithm):
                            settings.IncreaseAlgorithm = (IncreaseAlgorithm)reader.GetInt32();
                            break;
                        case nameof(settings.QuickUpdateKeyBinding):
                            settings.QuickUpdateKeyBinding = ReadKetGesture(ref reader);
                            break;
                        case nameof(settings.ForceQuitKeyBinding):
                            settings.ForceQuitKeyBinding = ReadKetGesture(ref reader);
                            break;
                        case nameof(settings.ExhaleKeyBinding):
                            settings.ExhaleKeyBinding = ReadKetGesture(ref reader);
                            break;
                    }
                }
            }

            throw new JsonException();
        }

        public override void Write(Utf8JsonWriter writer, Settings value, JsonSerializerOptions options)
        {
            writer.WriteStartObject();

            writer.WriteBoolean(nameof(value.Startup), value.Startup);
            writer.WriteBoolean(nameof(value.TaskbarIconVisible), value.TaskbarIconVisible);
            writer.WriteNumber(nameof(value.IncreaseMode), Convert.ToDecimal(value.IncreaseMode));
            writer.WriteNumber(nameof(value.IncreaseAlgorithm), Convert.ToDecimal(value.IncreaseAlgorithm));

            writer.WriteStartObject(nameof(value.QuickUpdateKeyBinding));
            writer.WriteNumber(nameof(value.QuickUpdateKeyBinding.Modifiers), Convert.ToDecimal(value.QuickUpdateKeyBinding.Modifiers));
            writer.WriteNumber(nameof(value.QuickUpdateKeyBinding.Key), Convert.ToDecimal(value.QuickUpdateKeyBinding.Key));
            writer.WriteEndObject();

            writer.WriteStartObject(nameof(value.ForceQuitKeyBinding));
            writer.WriteNumber(nameof(value.ForceQuitKeyBinding.Modifiers), Convert.ToDecimal(value.ForceQuitKeyBinding.Modifiers));
            writer.WriteNumber(nameof(value.ForceQuitKeyBinding.Key), Convert.ToDecimal(value.ForceQuitKeyBinding.Key));
            writer.WriteEndObject();

            writer.WriteStartObject(nameof(value.ExhaleKeyBinding));
            writer.WriteNumber(nameof(value.ExhaleKeyBinding.Modifiers), Convert.ToDecimal(value.ExhaleKeyBinding.Modifiers));
            writer.WriteNumber(nameof(value.ExhaleKeyBinding.Key), Convert.ToDecimal(value.ExhaleKeyBinding.Key));
            writer.WriteEndObject();

            writer.WriteEndObject();
        }

        private static KeyGesture ReadKetGesture(ref Utf8JsonReader reader)
        {
            Key key = Key.None;
            ModifierKeys modifiers = ModifierKeys.None;
            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.EndObject)
                {
                    return new KeyGesture(key, modifiers);
                }

                if (reader.TokenType == JsonTokenType.PropertyName)
                {
                    var propertyName = reader.GetString();

                    reader.Read();
                    switch (propertyName)
                    {
                        case "Key":
                            key = (Key)reader.GetInt32();
                            break;
                        case "Modifiers":
                            modifiers = (ModifierKeys)reader.GetInt32();
                            break;
                    }
                }
            }

            return new KeyGesture(key, modifiers);
        }
    }
}